home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / gnu / oleo_src.lha / src / io_disp.c < prev    next >
C/C++ Source or Header  |  1992-08-31  |  49KB  |  2,479 lines

  1. /*    Copyright (C) 1990 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "funcdef.h"
  20.  
  21. #include <fcntl.h>
  22. #include <errno.h>
  23. #include <ctype.h>
  24.  
  25. #ifdef __TURBOC__
  26. #include <conio.h>
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29.  
  30. #define COLS 80
  31. #define LINES 24
  32.  
  33. #define endwin()    clrscr()
  34. #define initscr()
  35. #define scrollok(x,y)
  36. #define cbreak()
  37. #define noecho()
  38. #define nonl()
  39. #define nl()
  40. #define refresh()
  41. #define mvaddch(r,c,ch)    move(r,c),addch(ch)
  42. #define mvaddstr(r,c,st) move(r,c),addstr(st)
  43. #define clear()        clrscr()
  44. #define clrtoeol()    clreol()
  45. #define addstr(str)    cputs(str)
  46. #define addch(ch)    putch(ch)
  47. #define move(y,x)    gotoxy(x+1,y+1)
  48. #define getyx(nul,yy,xx) yy=wherey()-1,xx=wherex()-1
  49. #define delch()        movetext(col+2,1,COLS,1,col+1,1),puttext(80,1,80,1,blank_text)
  50. #define insch(ch)    movetext(col,1,COLS-1,1,col+1,1),putch(ch)
  51. #define standout()    textattr(0x7<<4)
  52. #define standend()    textattr(0x7)
  53. #define beep()        putchar('\007')
  54. #define stdscr    0
  55. static void hack_standout EXT4(int, int, int, int);
  56. static char blank_text[] = { ' ', 0x07 };
  57. static void printw();
  58.  
  59. #else
  60. #undef USG
  61. #undef NULL
  62. #include <curses.h>
  63.  
  64. extern void tputs();
  65.  
  66. extern int wclear();
  67. extern int wrefresh();
  68. extern int endwin();
  69. extern int wmove();
  70. extern int wclrtoeol();
  71. extern int printw();
  72. extern int wdelch();
  73. extern int waddch();
  74. extern int winsch();
  75. extern int waddstr();
  76. #ifndef amiga
  77. extern int wstandout();
  78. extern int wstandend();
  79. #endif
  80. static void beep();
  81.  
  82. #endif
  83. #include "sysdef.h"
  84.  
  85. #include "global.h"
  86. #include "cell.h"
  87. #include "kbd.h"
  88.  
  89. /* This must agree with io_term.c */
  90. struct line {
  91.     int alloc;
  92.     char *buf;
  93. };
  94.  
  95. /* Window flags:
  96.     0x01    Locked horizontally
  97.     0x02    Locked vertically
  98.     0x04    Page Horizontally
  99.     0x08    Page Vertically
  100.     0x10    Edges disabled
  101.     0x20    Edges standout
  102.  */
  103. #define WIN_LCK_HZ    0x01
  104. #define WIN_LCK_VT    0x02
  105. #define WIN_PAG_HZ    0x04
  106. #define WIN_PAG_VT    0x08
  107. #define WIN_EDGES    0x10
  108. #define WIN_EDGE_REV    0x20
  109.  
  110. #define MIN_WIN_HEIGHT    (cwin->win_flags&WIN_EDGES ? 2 : 1)
  111. #define MIN_WIN_WIDTH    (cwin->win_flags&WIN_EDGES ? 6 : 1)
  112.  
  113. struct window {
  114.     struct rng screen;        /* Cells that are onscreen in this
  115.                        window */
  116.     VOIDSTAR *win_slops;        /* Slops in this window */
  117.     int win_over;        /* Where the data in this window starts */
  118.     int win_down;        /* on the screen.  */
  119.  
  120.     int win_flags;            /* Various flags */
  121.  
  122.         /* -1 if this window isn't linked to any others, else
  123.            contains the index into wins of the window this one is
  124.             linked to */
  125.     int win_linked;
  126.  
  127.         /* Number of lines of spreadsheet that can fit in this window.
  128.            This only changes when the screen is resized,
  129.            win->flags&WIN_EDGES changes, or a window is either
  130.             created or destroyed */
  131.     int numr;
  132.  
  133.         /* Number of text columns that can fit in this window.
  134.            This changes when the screen is resized,
  135.            win->flags&WIN_EDGES changes, a window is created or
  136.            destoryed, or win->lh_wid changes.  In the last case
  137.            win->numc+win->lh_wid remains a constant. */
  138.     int numc;
  139.  
  140.         /* Number of characters taken up by the row numbers at the
  141.            left hand edge of the screen.  Zero if edges is
  142.            win->flags&WIN_EDGES is off (by definition).  Seven (or
  143.            five) if win->flags&WIN_PAG_HZ (to make things easier).
  144.            Ranges between three "R9 " to seven "R32767 " depending on
  145.            the number of the highest row on the screen.  */
  146.     int lh_wid;
  147.  
  148.         /* Cursor row/column in this window */
  149.         /* Note that the external variables curow, cucol are used for
  150.            the currently active cursor position, so if you want
  151.            cwin->curow and cwin->cucol to be accurate, you have to
  152.            set them yourself. */
  153.     CELLREF curow,cucol;
  154. };
  155.  
  156. #define LINE_MIN 28
  157.  
  158. /* in io_utils.c */
  159. extern void flush_slops EXT1(VOIDSTAR);
  160. extern int find_slop EXT5(VOIDSTAR, CELLREF, CELLREF, CELLREF *, CELLREF *);
  161. extern void kill_slop EXT4(VOIDSTAR, CELLREF, CELLREF, CELLREF);
  162. extern void change_slop EXT6(VOIDSTAR, CELLREF, CELLREF, CELLREF, CELLREF, CELLREF);
  163. extern void set_slop EXT4(VOIDSTAR *, CELLREF, CELLREF, CELLREF);
  164.  
  165. extern char *print_cell EXT1(CELL *);
  166. extern char *adjust_prc EXT5(char *, CELL *, int, int, int);
  167.  
  168. extern char *cell_value_string EXT2(CELLREF, CELLREF);
  169.  
  170. /* in io_term.c */
  171. extern void set_line EXT2(struct line *,char *);
  172. extern int get_chr EXT0();
  173. extern int global_cmd EXT1(int);
  174.  
  175. extern struct keymap main_map;
  176. extern struct keymap meta_map[];
  177. extern int topclear;
  178. extern CELLREF mkrow,mkcol;
  179. extern CELLREF setrow,setcol;
  180. extern unsigned int how_many;
  181. extern const int rowmagic[],colmagic[];
  182. #ifdef TEST
  183. extern int dbg_do_stderr;
  184. #endif
  185.  
  186. /* in regions.c */
  187. extern void set_rng EXT5(struct rng *,CELLREF, CELLREF, CELLREF, CELLREF);
  188.  
  189. void cur_status EXT0();
  190. void pr_cell EXT3(CELLREF, CELLREF, CELL *);
  191. void set_numcols EXT2(struct window *, CELLREF);
  192. void disp_scrn EXT0();
  193.  
  194. static void find_nonzero_width EXT1(struct window *);
  195. static void hide_cell_cursor EXT0();
  196. static void display_cell_cursor EXT0();
  197.  
  198. static void recenter_window EXT1(struct window *);
  199. static void pr_cell_win EXT4(struct window *, CELLREF, CELLREF, CELL *);
  200.  
  201. /* Constants */
  202. const char numb_oflo[] ="\
  203. ##############################################################################\
  204. ##############################################################################\
  205. ##############################################################################\
  206. ######";
  207.  
  208.  
  209. static int nwin;
  210. static struct window *wins;
  211. static struct window *cwin;
  212.  
  213. int status = 2;
  214. int input = 1;
  215.  
  216. int redrew = 0;
  217. int textout = 0;
  218.  
  219. #define TOPLN    0x2
  220. #undef CTRL
  221. #define CTRL(X) ((X)&037)
  222. #define META(X) ((X)|0200)
  223.  
  224. #define L_TOGGLE_OVER     0
  225. #define L_BEG_LINE     1
  226. #define L_END_LINE     2
  227. #define L_BK_CHR     3
  228. #define L_BK_WORD     4
  229. #define L_BK_DEL_CHR     5
  230. #define L_BK_DEL_WORD     6
  231. #define L_BK_DEL_END     7
  232. #define L_FW_CHR     8
  233. #define L_FW_WORD     9
  234. #define L_FW_DEL_CHR    10
  235. #define L_FW_DEL_WORD    11
  236. #define L_FW_DEL_END    12
  237. #define L_FINISH    13
  238. #define L_INS_EXPR    14
  239. #define L_INS_VAL    15
  240. #define L_INS_REL    16
  241. #define L_INS_ABS    17
  242. #define L_INS_CHR    18
  243.  
  244. struct cmd_func edit_funcs[] = {
  245. {    "toggle-over-write",    0,    TOPLN,    0 },
  246. {    "cursor-begin-line",    0,    TOPLN,    0 },
  247. {    "cursor-end-line",    0,    TOPLN,    0 },
  248. {    "cursor-back-char",    "n",    TOPLN,    0 },
  249. {    "cursor-back-word",    "n",    TOPLN,    0 },
  250. {    "delete-prev-char",    "n",    TOPLN,    0 },
  251. {    "delete-prev-word",    "n",    TOPLN,    0 },
  252. {    "delete-to-start",    0,    TOPLN,    0 },
  253. {    "cursor-fwd-char",    "n",    TOPLN,    0 },
  254. {    "cursor-fwd-word",    "n",    TOPLN,    0 },
  255. {    "delete-next-char",    "n",    TOPLN,    0 },
  256. {    "delete-next-word",    "n",    TOPLN,    0 },
  257. {    "delete-to-end",    0,    TOPLN,    0 },
  258. {    "finish-line",        0,    TOPLN,    0 },
  259. {    "insert-cell-expression",0,    TOPLN,    0 },
  260. {    "insert-cell-value",    0,    TOPLN,    0 },
  261. {    "insert-rel-ref",    0,    TOPLN,    0 },
  262. {    "insert-abs-ref",    0,    TOPLN,    0 },
  263. {    "insert-character",    "T",    TOPLN,  0 },
  264. {            0,    0,    0,    0 }
  265. };
  266.  
  267. static struct key edit_keys[] = {
  268.     { 1,    L_BEG_LINE },        /* ^A */
  269.     { 1,    L_BK_CHR },
  270.     { 0,    UNBOUND },
  271.     { 1,    L_FW_DEL_CHR },
  272.     { 1,    L_END_LINE },        /* ^E */
  273.     { 1,    L_FW_CHR },
  274.     { 0,    UNBOUND },
  275.     { 1,    L_BK_DEL_CHR },
  276.     { 0,    UNBOUND },        /* ^I */
  277.     { 1,    L_FINISH },
  278.     { 1,    L_FW_DEL_END },
  279.     { 0,    UNBOUND },
  280.     { 1,    L_FINISH },        /* ^M */
  281.     { 0,    UNBOUND },
  282.     { 1,    L_TOGGLE_OVER },
  283.     { 0,    UNBOUND },
  284.     { 0,    UNBOUND },        /* ^Q */
  285.     { 0,    UNBOUND },
  286.     { 0,    UNBOUND },
  287.     { 0,    UNBOUND },
  288.     { 1,    L_BK_DEL_END },        /* ^U */
  289.     { 0,    UNBOUND },
  290.     { 0,    UNBOUND },
  291.     { 0,    UNBOUND },
  292.     { 0,    UNBOUND },
  293.     { 0,    UNBOUND },
  294.     { 255,    3 }
  295. };
  296. static struct key edit_1_keys[] = {
  297.     { 1,    L_INS_CHR }
  298. };
  299. static struct key edit_2_keys[] = {
  300.     { 1,    L_BK_DEL_CHR }
  301. };
  302.  
  303. struct keymap edit_map[] = {
  304.     {
  305.         &edit_map[1],    0,    0,    1,
  306.         CTRL('A'),    CTRL('['),
  307.         &edit_keys[0]
  308.     }, {
  309.         &edit_map[2],    0,    1,    1,
  310.         ' ',    '~',
  311.         &edit_1_keys[0]
  312.     },{
  313.         &main_map,    1,    0,    1,
  314.         '\177', '\177',
  315.         &edit_2_keys[0]
  316.     }
  317. };
  318.  
  319. /* Beginning of the edit meta-keymap  This is a sparse keymap */
  320. static struct key emk3[] = {
  321.     { 1, L_BK_DEL_WORD }
  322. };
  323. static struct key emk2[] = {
  324.     { 1, L_INS_REL },
  325.     { 0, UNBOUND },
  326.     { 0, UNBOUND },
  327.     { 0, UNBOUND },
  328.     { 1, L_INS_VAL }
  329. };
  330. static struct key emk1[] = {
  331.     { 1, L_INS_ABS },
  332.     { 1, L_BK_WORD },
  333.     { 0, UNBOUND },
  334.     { 1, L_FW_DEL_WORD },
  335.     { 1, L_INS_EXPR },
  336.     { 1, L_FW_WORD },
  337. };
  338.  
  339. struct keymap edit_meta_map[] = {
  340.     {
  341.         &edit_meta_map[1],    0,    0,    0,
  342.         CTRL('H'), CTRL('H'),
  343.         &emk3[0]
  344.     },{
  345.         &edit_meta_map[2],    0,    0,    0,
  346.         'A',    'F',
  347.         &emk1[0]
  348.     },{
  349.         &edit_meta_map[3],    0,    0,    0,
  350.         'R', 'V',
  351.         &emk2[0]
  352.     },{
  353.         &edit_meta_map[4],    0,    0,    0,
  354.         'a',    'f',
  355.         &emk1[0]
  356.     },{
  357.         &edit_meta_map[5],    0,    0,    0,
  358.         'r', 'v',
  359.         &emk2[0]
  360.     },{
  361.         &meta_map[0],        1,    0,    0,
  362.         '\177', '\177',
  363.         &emk3[0]
  364.     }
  365.  
  366. };
  367.  
  368. void
  369. open_display FUN1(int,c)
  370. {
  371.     extern unsigned short print_width;
  372.  
  373.     initscr();
  374.     scrollok(stdscr,0);
  375. #if !defined(__TURBOC__) && !defined(SYSV) && !defined(AMIGA)
  376.     if(c || !strncmp(getenv("TERM"),"xterm",5)) {
  377.         extern int stty EXT2(int, struct sgttyb *);
  378.  
  379.         _tty.sg_ispeed=15;_tty.sg_ospeed=15;stty(_tty_ch,&_tty);
  380.     }
  381. #endif
  382.  
  383.     cbreak();
  384.     noecho();
  385.     nonl();
  386.  
  387.     /* Must be after initscr() */
  388.     print_width=COLS;
  389.     nwin=1;
  390.     wins=cwin=ck_malloc(sizeof(struct window));
  391.     cwin->win_slops=(void *)0;
  392.     wins->win_over=0;
  393.     wins->win_down=3;
  394.     /* wins->win_edges=1; */
  395.     wins->win_flags= WIN_EDGES|WIN_EDGE_REV;
  396.     wins->win_linked= -1;
  397.     wins->numc=COLS;
  398.     wins->numr=LINES-3;
  399.     wins->lh_wid=0;
  400.     curow=wins->curow=MIN_ROW;
  401.     cucol=wins->cucol=MIN_COL;
  402. }
  403.  
  404. void
  405. close_display FUN0()
  406. {
  407.     clear();
  408.     refresh();
  409.     (void)endwin();
  410. }
  411.  
  412. void
  413. clear_top_before FUN0()
  414. {
  415.     textout=0;
  416.     if(topclear==2) {
  417.         move(input-1,0);
  418.         clrtoeol();
  419.         topclear=0;
  420.     }
  421.     move(0,0);
  422. }
  423.  
  424. void
  425. clear_top_after FUN0()
  426. {
  427.     move(input-1,0);
  428.     clrtoeol();
  429.     topclear=0;
  430. }
  431.  
  432. void
  433. redisp FUN0()
  434. {
  435.     refresh();
  436. }
  437.  
  438. static int nline;
  439. static int save_auto;
  440. extern int auto_recalc;
  441.  
  442. void
  443. text_start FUN0()
  444. {
  445.     clear();
  446.     redisp();
  447.     nline=0;
  448.     save_auto=auto_recalc;
  449.     auto_recalc=0;
  450.     redrew++;
  451. }
  452.  
  453. void
  454. text_line FUN1N(char *,ptr)
  455. {
  456.     va_list ap;
  457.     char sav;
  458.     char buf[1000];
  459.  
  460.     var_start(ap,ptr);
  461.     vsprintf(buf,ptr,ap);
  462.     va_end(ap);
  463.     ptr=buf;
  464.  
  465.     for(;;) {
  466.         if(nline==LINES-1) {
  467.             move(nline,0);
  468.             addstr("Press a key to to proceed:  ");
  469.             refresh();
  470.             (void)get_chr();
  471.             clear();
  472.             nline=0;
  473.         }
  474.         move(nline++,0);
  475.         if(strlen(ptr)<=COLS) {
  476.             addstr(ptr);
  477.             break;
  478.         }
  479.         sav=ptr[COLS];
  480.         ptr[COLS]='\0';
  481.         addstr(ptr);
  482.         ptr[COLS]=sav;
  483.         refresh();
  484.         ptr+=COLS;
  485.     }
  486. }
  487. void
  488. text_finish FUN0()
  489. {
  490.  
  491.     if(nline!=0) {
  492.         move(nline,0);
  493.         addstr("Press a key to continue:  ");
  494.         refresh();
  495.         (void)get_chr();
  496.     }
  497.     auto_recalc=save_auto;
  498.     disp_scrn();
  499. }
  500.  
  501. /* Return zero on success,
  502.     one on empty input,
  503.     and two on abort */
  504. int
  505. get_inp_line FUN2(char *,prompt, struct line *,line)
  506. {
  507.     static int over;    /* Overwrite or insert */
  508.  
  509.     char *ptr;        /* Current position in the line */
  510.     char *sptr;        /* Start of the line */
  511.     char *eptr;        /* End of the line */
  512.     int line_len;        /* length of the line */
  513.  
  514.     int col = 0;        /* Current cursor column */
  515.     int plen;        /* Length of the prompt */
  516.  
  517.     int domove = 0;
  518.     int doscroll = 0;
  519.  
  520.     int c;
  521.     int sfilled;
  522.  
  523.     char *in_str;
  524.     int n;
  525.     int do_free;
  526.     char vbuf[50];
  527.     extern char *macro_func_arg;
  528.     extern struct cmd_func *cur_cmd;
  529.     extern int cur_chr;
  530.     extern unsigned char cur_vector;
  531.  
  532. #define BUFFER 10
  533.  
  534. #define MORE(bytes)                    \
  535.     line_len+=bytes;                \
  536.     line->buf=ck_realloc(sptr,line_len+1);        \
  537.     eptr= eptr-sptr + line->buf;            \
  538.     ptr= ptr-sptr + line->buf;            \
  539.     sptr= line->buf;                \
  540.  
  541. #define KILLCH()                \
  542. {                        \
  543.     if(ptr!=eptr) {                \
  544.         char *tptr;            \
  545.         for(tptr=ptr;tptr<=eptr;tptr++) \
  546.             tptr[-1]= tptr[0];    \
  547.     }                    \
  548.     --ptr;                    \
  549.     --eptr;                    \
  550.     --sfilled;                \
  551.     --col;                    \
  552.     if(col<BUFFER)                \
  553.         doscroll++;            \
  554.     else if(!doscroll) {            \
  555.         move(input-1,col);        \
  556.         delch();            \
  557.         if(eptr-sptr+plen>=COLS && ptr+(COLS-1-col)<eptr) {    \
  558.             mvaddch(input-1,COLS-1,ptr[COLS-1-col]);\
  559.             domove++;        \
  560.         }                \
  561.     }                    \
  562. }
  563.  
  564.     topclear=2;
  565.  
  566.     if(macro_func_arg) {
  567.         set_line(line,macro_func_arg);
  568.         macro_func_arg=0;
  569.         return 0;
  570.     }
  571.     if(!line->alloc) {
  572.         line->alloc=LINE_MIN;
  573.         line->buf=ck_malloc(LINE_MIN);
  574.         line->buf[0]='\0';
  575.     }
  576.     line_len=line->alloc-1;        /* Leave room for the NULL */
  577.     sptr=line->buf;
  578.  
  579.     sfilled=strlen(sptr);
  580.     plen=strlen(prompt)+3;
  581.     ptr=sptr+sfilled;
  582.     eptr=ptr;
  583.     over=0;
  584.  
  585.     doscroll++;
  586.     for(;;) {
  587.         if(domove) {
  588.             domove=0;
  589.             if(col<BUFFER || col>COLS-BUFFER)
  590.                 doscroll++;
  591.             else
  592.                 move(input-1,col);
  593.         }
  594.         if(doscroll) {
  595.             doscroll=0;
  596.             redrew=0;
  597.             if(textout==2) {
  598.                 /* [MORE] the error msg, so the luser has
  599.                    a chance to see it. . . */
  600.                 mvaddstr(input-1,COLS-7,"[MORE]");
  601.                 (void)get_chr();
  602.             }
  603.             textout=0;
  604.             move(input-1,0);
  605.             clrtoeol();
  606.             if(plen + (ptr-sptr)<COLS-BUFFER) {
  607.                 *eptr=0;
  608.                 printw("%s:  %.*s",prompt,COLS-plen,sptr);
  609.                 col=plen+(ptr-sptr);
  610.             } else {
  611.                 char *p;
  612.                 p=sptr+COLS-2*BUFFER-plen;
  613.                 while(ptr-p>=COLS-BUFFER)
  614.                     p+=COLS-2*BUFFER;
  615.                 *eptr=0;
  616.                 printw("%.*s",COLS,p);
  617.                 col=ptr-p;
  618.             }
  619.             move(input-1,col);
  620.         }
  621.         if(how_many!=1) {
  622.             how_many=1;
  623.             cur_status();
  624.             move(input-1,col);
  625.         }
  626.         map_chr(EDIT_MAP);
  627.  swtch:
  628.         if(cur_vector!=1) {
  629.             n=global_cmd(EDIT_MAP);
  630.             if(redrew || textout)
  631.                 doscroll++;
  632.             if(n==-3) {
  633.                 *eptr++='\0';
  634.                 return 2;
  635.             } else if(n==-2) {
  636.                 beep();
  637.                 beep();
  638.             } else if(n>=0)
  639.                 goto swtch;
  640.             continue;
  641.         }
  642.         switch(cur_cmd-edit_funcs) {
  643.         case L_BEG_LINE:
  644.             col-=ptr-sptr;
  645.             ptr=sptr;
  646.             domove++;
  647.             break;
  648.  
  649.         case L_BK_CHR:
  650.             for(n=0;ptr!=sptr && n<how_many;n++) {
  651.                 --ptr;
  652.                 --col;
  653.             }
  654.             domove++;
  655.             break;
  656.  
  657.         case L_BK_WORD:
  658.             for(n=0;ptr!=sptr && n<how_many;n++) {
  659.                 while(ptr!=sptr && !isalnum(ptr[-1])) {
  660.                     --ptr;
  661.                     --col;
  662.                 }
  663.                 while(ptr!=sptr && isalnum(ptr[-1])) {
  664.                     --ptr;
  665.                     --col;
  666.                 }
  667.             }
  668.             domove++;
  669.             break;
  670.  
  671.         case L_FW_DEL_CHR:
  672.             for(n=0;ptr!=eptr && n<how_many;n++) {
  673.                 ptr++;
  674.                 col++;
  675.                 KILLCH()
  676.             }
  677.             break;
  678.  
  679.         case L_FW_DEL_WORD:
  680.             for(n=0;ptr!=eptr && n<how_many;n++) {
  681.                 while(ptr!=eptr && !isalnum(ptr[0])) {
  682.                     ptr++;
  683.                     col++;
  684.                     KILLCH()
  685.                 }
  686.                 while(ptr!=eptr && isalnum(ptr[0])) {
  687.                     ptr++;
  688.                     col++;
  689.                     KILLCH()
  690.  
  691.                 }
  692.             }
  693.             break;
  694.  
  695.         case L_END_LINE:
  696.             col+=eptr-ptr;
  697.             ptr=eptr;
  698.             domove++;
  699.             break;
  700.  
  701.         case L_FW_CHR:
  702.             for(n=0;ptr!=eptr && n<how_many;n++) {
  703.                 col++;
  704.                 ptr++;
  705.             }
  706.             domove++;
  707.             break;
  708.  
  709.         case L_FW_WORD:
  710.             for(n=0;ptr!=eptr && n<how_many;n++) {
  711.                 while(ptr!=eptr && !isalnum(ptr[0])) {
  712.                     col++;
  713.                     ptr++;
  714.                 }
  715.                 while(ptr!=eptr && isalnum(ptr[0])) {
  716.                     col++;
  717.                     ptr++;
  718.                 }
  719.             }
  720.             domove++;
  721.             break;
  722.  
  723.         case L_FW_DEL_END:
  724.             eptr=ptr;
  725.             clrtoeol();
  726.             break;
  727.  
  728.         case L_TOGGLE_OVER:
  729.             over= !over;
  730.             break;
  731.  
  732.         case L_BK_DEL_WORD:
  733.             for(n=0;ptr!=sptr && n<how_many;n++) {
  734.                 while(ptr!=sptr && !isalnum(ptr[-1]))
  735.                     KILLCH()
  736.  
  737.                 while(ptr!=sptr && isalnum(ptr[-1]))
  738.                     KILLCH()
  739.             }
  740.  
  741.             break;
  742.  
  743.         case L_BK_DEL_END:
  744.             while(ptr!=sptr)
  745.                 KILLCH()
  746.             break;
  747.  
  748.         case L_BK_DEL_CHR:
  749.             for(n=0;ptr!=sptr && n<how_many;n++)
  750.                 KILLCH()
  751.             break;
  752.  
  753.  
  754.         case L_FINISH:
  755.             *eptr++='\0';
  756.             textout=1;
  757.             return eptr-sptr==1 ? 1 : 0;
  758.  
  759.         case L_INS_EXPR:
  760.         {
  761.             CELL *cp;
  762.  
  763.             if(!(cp=find_cell(curow,cucol)))
  764.                 break;
  765.             in_str=decomp(curow,cucol,cp);
  766.             do_free=1;
  767.         }
  768.             goto insert_string;
  769.  
  770.         case L_INS_VAL:
  771.             in_str=cell_value_string(curow,cucol);
  772.             do_free=0;
  773.             goto insert_string;
  774.  
  775.         case L_INS_REL:
  776. #ifdef A0_REFS
  777.             if(mkrow!=NON_ROW) {
  778.                 struct rng r;
  779.  
  780.                 set_rng(&r,curow,cucol,mkrow,mkcol);
  781.                 in_str=range_name(&r);
  782.             } else
  783.                 in_str=cell_name(curow,cucol);
  784. #else
  785.             if(mkrow!=NON_ROW) {
  786.                 switch(   ((curow==setrow)<<3)
  787.                     + ((mkrow==setrow)<<2)
  788.                      + ((cucol==setcol)<<1)
  789.                      + (mkcol==setcol)) {
  790.                 case 0:
  791.                 case 1:
  792.                 case 2:
  793.                 case 4:
  794.                 case 5:
  795.                 case 6:
  796.                 case 8:
  797.                 case 9:
  798.                 case 10:
  799.                     sprintf(vbuf,"r[%+d:%+d]c[%+d:%+d]",
  800.                         (curow < mkrow ? curow : mkrow) - setrow,
  801.                         (curow < mkrow ? mkrow : curow) - setrow,
  802.                         (cucol < mkcol ? cucol : mkcol) - setcol,
  803.                         (cucol < mkcol ? mkcol : cucol) - setcol);
  804.                     break;
  805.                 case 3:
  806.                 case 7:
  807.                 case 11:
  808.                     sprintf(vbuf,"r[%+d:%+d]c",
  809.                         (curow < mkrow ? curow : mkrow) - setrow,
  810.                         (curow < mkrow ? mkrow : curow) - setrow);
  811.                     break;
  812.                 case 12:
  813.                 case 14:
  814.                 case 13:
  815.                     sprintf(vbuf,"rc[%+d:%+d]",
  816.                         (cucol < mkcol ? cucol : mkcol) - setcol,
  817.                         (cucol < mkcol ? mkcol : cucol) - setcol);
  818.                     break;
  819.                 case 15:
  820.                     strcpy(vbuf,"rc");
  821.                     break;
  822. #ifdef TEST
  823.                 default:
  824.                     panic("Unknown value");
  825. #endif
  826.                 }
  827.             } else {
  828.                 switch(((curow==setrow)<<1) + (cucol==setcol)) {
  829.                 case 0:
  830.                     sprintf(vbuf,"r[%+d]c[%+d]",curow-setrow,cucol-setcol);
  831.                     break;
  832.                 case 1:
  833.                     sprintf(vbuf,"r[%+d]c",curow-setrow);
  834.                     break;
  835.                 case 2:
  836.                     sprintf(vbuf,"rc[%+d]",cucol-setcol);
  837.                     break;
  838.                 case 3:
  839.                     strcpy(vbuf,"rc");
  840.                     break;
  841. #ifdef TEST
  842.                 default:
  843.                     panic("huh what");
  844. #endif
  845.                 }
  846.             }
  847.             in_str=vbuf;
  848. #endif
  849.             do_free=0;
  850.             goto insert_string;
  851.  
  852.         case L_INS_ABS:
  853.             /* Insert current cell/range name as an absolute reference */
  854. #ifdef A0_REFS
  855.             if(mkrow!=NON_ROW)
  856.                 sprintf(vbuf,"$%s$%u:$%s:$%u",col_to_str(cucol),curow,col_to_str(mkcol),mkrow);
  857.             else
  858.                 sprintf(vbuf,"$%s$%u",col_to_str(cucol), curow);
  859.             in_str=vbuf;
  860. #else
  861.             if(mkrow!=NON_ROW) {
  862.                 struct rng r;
  863.  
  864.                 set_rng(&r,curow,cucol,mkrow,mkcol);
  865.                 in_str=range_name(&r);
  866.             } else
  867.                 in_str=cell_name(curow,cucol);
  868. #endif
  869.             do_free=0;
  870.  
  871.         insert_string:
  872.             c=strlen(in_str);
  873.             if((sfilled + (over ? c + (ptr-eptr) : c)) >= line_len) {
  874.                 n= over ? c + (ptr-eptr) : c;
  875.                 if(n<LINE_MIN)
  876.                     n=LINE_MIN;
  877.                 MORE(n);
  878.             }
  879.             if(over) {
  880.                 if(ptr+c>eptr) {
  881.                     sfilled+=(ptr+c)-eptr;
  882.                     eptr=ptr+c;
  883.                 }
  884.             } else {
  885.                 if(ptr!=eptr) {
  886.                     char *tptr;
  887.  
  888.                     for(tptr=eptr;tptr>=ptr;--tptr)
  889.                         tptr[c]=tptr[0];
  890.                 }
  891.                 eptr+=c;
  892.                 sfilled+=c;
  893.             }
  894.             bcopy(in_str,ptr,c);
  895.             ptr+=c;
  896.             if(col+c>=COLS-BUFFER) {
  897.                 doscroll++;
  898.             } else {
  899.                 col+=c;
  900.                 if(!over && ptr!=eptr) {
  901. #ifdef __TURBOC__
  902.                     movetext(col-c,1,COLS-c,1,col,1);
  903. #else
  904.                     while(c--)
  905.                         insch(' ');
  906. #endif
  907.                 }
  908.                 addstr(in_str);
  909.             }
  910.             if(do_free)
  911.                 decomp_free();
  912.             break;
  913.  
  914.         case L_INS_CHR:
  915.             if((sfilled+how_many + (over ? (ptr-eptr) : (0))) >= line_len) {
  916.                 n = over ? how_many+(ptr-eptr) : how_many;
  917.                 if(n<LINE_MIN)
  918.                     n=LINE_MIN;
  919.                 MORE(n);
  920.             }
  921.             if(over) {
  922.                 if(ptr+how_many>eptr) {
  923.                     sfilled+=(ptr+how_many)-eptr;
  924.                     eptr=ptr+how_many;
  925.                 }
  926.             } else {
  927.                 if(ptr!=eptr) {
  928.                     char *tptr;
  929.  
  930.                     for(tptr=eptr;tptr>=ptr;--tptr)
  931.                         tptr[how_many]=tptr[0];
  932.                 }
  933.                 eptr+=how_many;
  934.                 sfilled+=how_many;
  935.             }
  936.             for(n=0;n<how_many;n++)
  937.                 *ptr++=cur_chr;
  938.  
  939.             if(col+how_many>=COLS-BUFFER) {
  940.                 doscroll++;
  941.             } else if(over || ptr==eptr) {
  942.                 col+=how_many;
  943.                 for(n=0;n<how_many;n++)
  944.                     addch(cur_chr);
  945.             } else {
  946.                 col+=how_many;
  947.                 for(n=0;n<how_many;n++) {
  948.                     insch(cur_chr);
  949.                     move(input-1,col);
  950.                 }
  951.             }
  952.             break;
  953.         }
  954.     }
  955. #undef KILLCH
  956. #undef BUFFER
  957. #undef MORE
  958. }
  959.  
  960. /* External interface to window routines */
  961. /* Create a new window by splitting the current one. */
  962. void
  963. open_window FUN1(char *,text)
  964. {
  965.     int hv;
  966.     int where;
  967.     int tmp;
  968.     struct window *win;
  969.  
  970.     while(*text==' ')
  971.         text++;
  972.  
  973.     if(*text=='h' || *text=='H') {
  974.         hv=1;
  975.     } else if(*text=='v' || *text=='V') {
  976.         hv=0;
  977.     } else {
  978.         error_msg("Open 'h'orizontal or 'v'ertical window, not '%s'",text);
  979.         return;
  980.     }
  981.     where=atoi(text+1);
  982.  
  983.     if(   (!hv && (    where<MIN_WIN_WIDTH
  984.             || cwin->numc-where<MIN_WIN_WIDTH))
  985.        || ( hv && (    where<MIN_WIN_HEIGHT
  986.             || cwin->numr-where<MIN_WIN_HEIGHT))) {
  987.         error_msg("Window won't fit!");
  988.         return;
  989.     }
  990.     nwin++;
  991.     tmp=cwin-wins;
  992.  
  993.     wins=ck_realloc(wins,nwin*sizeof(struct window));
  994.     win= &wins[nwin-1];
  995.     win->win_slops=(void *)0;
  996.     cwin= &wins[tmp];
  997.     win->win_over=cwin->win_over + (hv ? 0 : where) - cwin->lh_wid;
  998.     win->win_down=cwin->win_down + (hv ? where : 0);
  999.     win->win_flags = cwin->win_flags;
  1000.     win->win_linked= -1;
  1001.     win->lh_wid=0;
  1002.     win->numc=cwin->numc + cwin->lh_wid + (hv ? 0 : -where);
  1003.     win->numr=cwin->numr + (hv ? -where : 0);
  1004.     win->curow=curow;
  1005.     win->cucol=cucol;
  1006.     set_numcols(win,curow);
  1007.     cwin->numc-=(hv ? 0 : win->numc+win->lh_wid);
  1008.     cwin->numr-=(hv ? (win->numr+(win->lh_wid?1:0)) : 0);
  1009.     cwin->curow=curow;
  1010.     cwin->cucol=cucol;
  1011.     hide_cell_cursor();
  1012.     win=cwin;
  1013.     cwin= &wins[nwin-1];
  1014.     recenter_window(cwin);
  1015.     recenter_window(win);
  1016.     disp_scrn();
  1017. }
  1018.  
  1019. static void do_close_window FUN1(int, num)
  1020. {
  1021.     int n;
  1022.     struct window *win,*kwin;
  1023.     int nlf,nrt,nup,nbl;
  1024.     int klo,kho,kld,khd;
  1025.     int lo,ho,ld,hd;
  1026.     struct tmp {
  1027.         int    l,
  1028.             r,
  1029.             u,
  1030.             b;
  1031.     } *tmpptr;
  1032.     void recenter_all_win EXT0();
  1033.  
  1034.     tmpptr=ck_malloc(sizeof(struct tmp)*nwin);
  1035.  
  1036.     kwin= &wins[num];
  1037.     nlf=nrt=nup=nbl=0;
  1038.     klo=kwin->win_over-kwin->lh_wid;
  1039.     kho=kwin->win_over+kwin->numc-1;
  1040.     kld=kwin->win_down-(kwin->lh_wid?1:0);
  1041.     khd=kwin->win_down+kwin->numr-1;
  1042.  
  1043.     for(win=wins;win<&wins[nwin];win++) {
  1044.         lo=win->win_over-win->lh_wid;
  1045.         ho=win->win_over+win->numc-1;
  1046.         ld=win->win_down-(win->lh_wid?1:0);
  1047.         hd=win->win_down+win->numr-1;
  1048.  
  1049.         /* Match to the left ? */
  1050.         if(lo==kho+1) {
  1051.             if(ld>=kld && hd<=khd)
  1052.                 tmpptr[nrt++].r=win-wins;
  1053.             else if(hd>=kld && ld<=khd)
  1054.                 nrt= nwin;
  1055.         }
  1056.         else if(ho==klo-1) {
  1057.             if(ld>=kld && hd<=khd)
  1058.                 tmpptr[nlf++].l=win-wins;
  1059.             else if(hd>=kld && ld<=khd)
  1060.                 nlf= nwin;
  1061.         }
  1062.         else if(ld==khd+1) {
  1063.             if(lo>=klo && ho<=kho)
  1064.                 tmpptr[nbl++].b=win-wins;
  1065.             else if(ho>=kho && lo<=kho)
  1066.                 nbl= nwin;
  1067.         }
  1068.         else if(hd==kld-1) {
  1069.             if(lo>=klo && ho<=kho)
  1070.                 tmpptr[nup++].u=win-wins;
  1071.             else if(ho>=kho && lo<=kho)
  1072.                 nup= nwin;
  1073.         }
  1074.  
  1075.     }
  1076.     if(nrt==0)
  1077.         nrt=nwin;
  1078.     if(nlf==0)
  1079.         nlf=nwin;
  1080.     if(nbl==0)
  1081.         nbl=nwin;
  1082.     if(nup==0)
  1083.         nup=nwin;
  1084.     if(nrt<=nlf && nrt<=nbl && nrt<=nup) {
  1085.         for(n=0;n<nrt;n++) {
  1086.             wins[tmpptr[n].r].numc+=kwin->lh_wid+kwin->numc;
  1087.             wins[tmpptr[n].r].win_over-=kwin->lh_wid+kwin->numc;
  1088.         }
  1089.     } else if(nlf<=nbl && nlf<=nup) {
  1090.         for(n=0;n<nlf;n++)
  1091.             wins[tmpptr[n].l].numc+=kwin->lh_wid+kwin->numc;
  1092.     } else if(nbl<=nup) {
  1093.         for(n=0;n<nbl;n++) {
  1094.             wins[tmpptr[n].b].numr+=kwin->numr+(kwin->lh_wid ? 1 : 0);
  1095.             wins[tmpptr[n].b].win_down-=kwin->numr+(kwin->lh_wid ? 1 : 0);
  1096.         }
  1097.     } else {
  1098.         for(n=0;n<nup;n++)
  1099.             wins[tmpptr[n].u].numr+=kwin->numr+(kwin->lh_wid ? 1 : 0);
  1100.     }
  1101.      if(kwin==cwin && kwin!= wins)
  1102.         --cwin;
  1103.     if(cwin==&wins[nwin-1])
  1104.         --cwin;
  1105.     while(kwin< &wins[nwin]) {
  1106.         *kwin= kwin[1];
  1107.         kwin++;
  1108.     }
  1109.     --nwin;
  1110.     recenter_all_win();
  1111.     return;
  1112. }
  1113.  
  1114. void
  1115. close_window FUN1(char *,text)
  1116. {
  1117.     int num;
  1118.  
  1119.     num=atoi(text)-1;
  1120.     if(num<0 || num>=nwin) {
  1121.         error_msg("Window %s?",text);
  1122.         return;
  1123.     }
  1124.     if(nwin==1) {
  1125.         error_msg("You can't close the last window!");
  1126.         return;
  1127.     }
  1128.     do_close_window(num);
  1129. }
  1130.  
  1131. void
  1132. goto_window FUN1(char *,text)
  1133. {
  1134.     int n;
  1135.  
  1136.     n=atoi(text)-1;
  1137.     if(n<0 || n>nwin) {
  1138.         error_msg("Window %s doesn't exist.",text);
  1139.         return;
  1140.     }
  1141.     hide_cell_cursor();
  1142.     cwin->curow=curow;
  1143.     cwin->cucol=cucol;
  1144.     cwin= &wins[n];
  1145.     curow=cwin->curow;
  1146.     cucol=cwin->cucol;
  1147.     display_cell_cursor();
  1148. }
  1149.  
  1150. static int locmp FUN2(struct window **,a, struct window **,b)
  1151. {
  1152.     return (*a)->win_down-(*b)->win_down;
  1153. }
  1154. static int hicmp FUN2(struct window **,a, struct window **,b)
  1155. {
  1156.     return ((*a)->win_down+(*a)->numr)-((*b)->win_down+(*b)->numr);
  1157. }
  1158.  
  1159. /* How this works:  First figure out how many lines are now avaliable for
  1160.    sheet data.  Then squeeze/stretch the windows to fit that space. . . */
  1161.  
  1162. static void resize_screen FUN0()
  1163. {
  1164.     int n;
  1165.     int nlines;
  1166.     int firstln;
  1167.     /* int shifted; */
  1168.     int lo,sq,hi;
  1169.     struct window **t;
  1170.  
  1171.     if(input<LINES/2) {
  1172.         if(status>LINES/2) {
  1173.             nlines=status-input-1;
  1174.             firstln=input+1;
  1175.         } else {
  1176.             firstln=1+input>status?input:status;
  1177.             nlines=LINES-firstln;
  1178.         }
  1179.     } else if(status<LINES/2) {
  1180.         nlines=input-status;
  1181.         firstln=status+1;
  1182.     } else {
  1183.         firstln=1;
  1184.         nlines=(input>status?status:input)-1;
  1185.     }
  1186.  
  1187.     t=ck_malloc(nwin*sizeof(struct window *));
  1188.     for(n=0;n<nwin;n++)
  1189.         t[n]= &wins[n];
  1190.     qsort(t,nwin,sizeof(struct window *),hicmp);
  1191.     hi=t[0]->win_down+t[0]->numr;
  1192.     sq=firstln+nlines-hi;
  1193.     for(n=0;n<nwin && hi==t[n]->win_down+t[0]->numr;n++) {
  1194.         t[n]->numr-=sq;
  1195.     }
  1196.     qsort(t,nwin,sizeof(struct window *),locmp);
  1197.     lo=t[0]->win_down;
  1198.     sq=firstln-lo+((t[0]->win_flags&WIN_EDGES)?1:0);
  1199.     for(n=0;n<nwin && t[n]->win_down==lo;n++) {
  1200.         t[n]->numr-=sq;
  1201.         t[n]->win_down=firstln+((t[0]->win_flags&WIN_EDGES)?1:0);
  1202.     }
  1203.     cwin->curow=curow;
  1204.     cwin->cucol=cucol;
  1205.     for(n=0;n<nwin;n++) {
  1206.         if(wins[n].numr<=0) {
  1207.             do_close_window(n);
  1208.             n--;
  1209.         } else
  1210.             recenter_window(&wins[n]);
  1211.     }
  1212.     disp_scrn();
  1213. }
  1214.  
  1215. #if 0
  1216. static void shift_screen FUN1(int, by)
  1217. {
  1218.     int n;
  1219.  
  1220.     for(n=0;n<nwin;n++)
  1221.         wins[n].win_down+=by;
  1222.     disp_scrn();
  1223. }
  1224. #endif
  1225.  
  1226. int
  1227. set_window_option FUN2(int,set_opt, char *,text)
  1228. {
  1229.     int n;
  1230.     static struct opt {
  1231.         char *text;
  1232.         int bits;
  1233.     } opts[] = {
  1234.         { "reverse",    WIN_EDGE_REV },
  1235.         { "standout",    WIN_EDGE_REV },
  1236.         { "page",    WIN_PAG_HZ|WIN_PAG_VT },
  1237.         { "pageh",    WIN_PAG_HZ },
  1238.         { "pagev",    WIN_PAG_VT },
  1239.         { "lockh",    WIN_LCK_HZ },
  1240.         { "lockv",    WIN_LCK_VT }
  1241.     };
  1242.     if(set_opt && !strincmp(text,"status ",7)) {
  1243.         n=atoi(text+7);
  1244.         if(n>LINES || n<-LINES) {
  1245.             error_msg("%s?",text);
  1246.             return 1;
  1247.         }
  1248.         if(n<0)
  1249.             n=LINES+1+n;
  1250.         status=n;
  1251.         resize_screen();
  1252.     } else if(set_opt && !strincmp(text,"input ",6)) {
  1253.         n=atoi(text+6);
  1254.         if(n==0 || n>LINES || n<-LINES) {
  1255.             error_msg("%s?",text);
  1256.             return 1;
  1257.         }
  1258.         if(n<0)
  1259.             n=LINES+1+n;
  1260.         input=n;
  1261.         resize_screen();
  1262.     } else if(!strincmp(text,"link",4)) {
  1263.         if(set_opt) {
  1264.             n=atoi(text+4)-1;
  1265.             if(n<0 || n>nwin)
  1266.                 error_msg("Can't '%s': window # out of range",text);
  1267.             else
  1268.                 cwin->win_linked= n;
  1269.         } else
  1270.             cwin->win_linked= -1;
  1271.     } else if(set_opt && !stricmp(text,"unlink")) {
  1272.         cwin->win_linked= -1;
  1273.     } else if(!stricmp(text,"edges")) {
  1274.         if(set_opt) {
  1275.             if((cwin->win_flags&WIN_EDGES)==0) {
  1276.                 if(cwin->numr<2 || cwin->numc<6)
  1277.                     error_msg("Edges wouldn't fit!");
  1278.                 cwin->win_flags|= WIN_EDGES;
  1279.                 cwin->win_down++;
  1280.                 cwin->numr--;
  1281.                 /* set_numcols(cwin,cwin->screen.hr); */
  1282.             }
  1283.         } else {
  1284.             if(cwin->win_flags&WIN_EDGES) {
  1285.                 cwin->win_flags&= ~WIN_EDGES;
  1286.                 cwin->win_over-=cwin->lh_wid;
  1287.                 cwin->numc+=cwin->lh_wid;
  1288.                 cwin->lh_wid=0;
  1289.                 cwin->win_down--;
  1290.                 cwin->numr++;
  1291.             }
  1292.         }
  1293.  
  1294.     } else if(set_opt && !strincmp(text,"row ",4)) {
  1295.         text+=4;
  1296.         curow=astol(&text);
  1297.     } else if(set_opt && !strincmp(text,"col ",4)) {
  1298.         text+=4;
  1299.         cucol=astol(&text);
  1300.     } else {
  1301.         for(n=0;n<sizeof(opts)/sizeof(struct opt);n++) {
  1302.             if(!stricmp(text,opts[n].text)) {
  1303.                 if(set_opt)
  1304.                     cwin->win_flags|= opts[n].bits;
  1305.                 else
  1306.                     cwin->win_flags&= ~opts[n].bits;
  1307.                 break;
  1308.             }
  1309.         }
  1310.         if(n==sizeof(opts)/sizeof(struct opt))
  1311.             return 0;
  1312.     }
  1313.     return 1;
  1314. }
  1315.  
  1316. void
  1317. show_window_options FUN0()
  1318. {
  1319.     int n;
  1320.     struct window *win;
  1321.  
  1322.     cwin->curow=curow;
  1323.     cwin->cucol=cucol;
  1324.     win= &wins[0];
  1325.     if(status)
  1326.         text_line("Status line at %d", status);
  1327.     else
  1328.         text_line("Status line disabled.");
  1329.     text_line("");
  1330.     for(n=0;n<nwin;n++) {
  1331.         text_line("Window #%d showing %s, with cursor at %s",
  1332.             n+1,
  1333.             range_name(&(win->screen)),
  1334.             cell_name(win->curow,win->cucol));
  1335.         text_line("   Options:  %sedges (%sreverse)%s%s%s%s",
  1336.             win->win_flags&WIN_EDGES    ? "" : "no",
  1337.             win->win_flags&WIN_EDGE_REV ? "" : "no",
  1338.             win->win_flags&WIN_PAG_HZ   ? ", pageh" : "",
  1339.             win->win_flags&WIN_PAG_VT   ? ", pagev" : "",
  1340.             win->win_flags&WIN_LCK_HZ   ? ", lockh" : "",
  1341.             win->win_flags&WIN_LCK_VT   ? ", lockv" : "");
  1342.         if(win->win_linked!=-1)
  1343.             text_line("Linked to window %d",win->win_linked+1);
  1344.         win++;
  1345.     }
  1346. }
  1347.  
  1348. #ifdef TEST
  1349. void
  1350. dbg_show_wins FUN0()
  1351. {
  1352.     int n;
  1353.  
  1354.     for(n=0;n<nwin;n++) {
  1355.         text_line("Window %d",n);
  1356.         text_line("  screen %s  slops %p  flags %x  linked %d",
  1357.  range_name(&(wins[n].screen)),wins[n].win_slops,wins[n].win_flags,
  1358.  wins[n].win_linked);
  1359.         text_line("  ov %d  dn %d  nr %d  nc %d  lh_wid %d  pos %s",wins[n].win_over,wins[n].win_down,wins[n].numr,wins[n].numc,wins[n].lh_wid,cell_name(wins[n].curow,wins[n].cucol));
  1360.         text_line("");
  1361.     }
  1362. }
  1363. #endif
  1364.         
  1365. void
  1366. disp_scrn FUN0()
  1367. {
  1368.     CELLREF cc,rr;
  1369.     int n,n1;
  1370.     CELL *cp;
  1371.     struct window *win;
  1372.  
  1373.     clear();
  1374.     redrew++;
  1375.     for(win=wins;win<&wins[nwin];win++) {
  1376.         if(win->lh_wid) {
  1377.             move(win->win_down-1,win->win_over-win->lh_wid);
  1378.             printw("#%*d ", win->lh_wid-2, 1+win-wins);
  1379.             if(win->win_flags&WIN_EDGE_REV)
  1380.                 standout();
  1381.             cc=win->screen.lc;
  1382.             do {
  1383.                 n=get_width(cc);
  1384.                 if(n>win->numc)
  1385.                     n=win->numc;
  1386.                 if(n>1) {
  1387.                     char *ptr;
  1388. #ifdef A0_REFS
  1389.                     ptr=col_to_str(cc);
  1390. #else
  1391.                     char buf[30];
  1392.  
  1393.                     sprintf(buf,"C%u",cc);
  1394.                     ptr=buf;
  1395. #endif
  1396.                     --n;
  1397.                     n1=strlen(ptr);
  1398.                     if(n<n1)
  1399.                         printw("%.*s ",n,"###############");
  1400.                     else {
  1401.                         n1=(n-n1)/2;
  1402.                         printw("%*s%-*s ",n1,"",n-n1,ptr);
  1403.                     }
  1404.                 } else if(n==1)
  1405.                     addstr("#");
  1406.             } while(cc++<win->screen.hc);
  1407.  
  1408.             rr=win->screen.lr;
  1409.             do {
  1410.                 move(rr+win->win_down-win->screen.lr,win->win_over-win->lh_wid);
  1411. #ifdef A0_REFS
  1412.                 printw("%-*d ",win->lh_wid-1,rr);
  1413. #else
  1414.                 printw("R%-*d",win->lh_wid-1,rr);
  1415. #endif
  1416.             } while(rr++<win->screen.hr);
  1417.  
  1418.             if(win->win_flags&WIN_EDGE_REV)
  1419.                 standend();
  1420.         }
  1421.         flush_slops(win->win_slops);
  1422.         find_cells_in_range(&(win->screen));
  1423.         while(cp=next_row_col_in_range(&rr,&cc))
  1424.             if(GET_TYP(cp))
  1425.               {
  1426.                 pr_cell_win(win,rr,cc,cp);
  1427.               }
  1428.     }
  1429.     if(!(cp=find_cell(curow,cucol)) || !GET_TYP(cp))
  1430.         display_cell_cursor();
  1431.     cur_status();
  1432. }
  1433.  
  1434. void
  1435. set_numcols FUN2(struct window *,win, CELLREF,hr)
  1436. {
  1437.     int lh;
  1438.  
  1439.     if((win->win_flags&WIN_EDGES)==0)
  1440.         lh=0;
  1441. #if BITS_PER_CELLREF>8
  1442.     else if((win->win_flags&WIN_PAG_HZ) || hr>=10000)
  1443.         lh=7;
  1444.     else if(hr>=1000)
  1445.         lh=6;
  1446.     else if(hr>=100)
  1447.         lh=5;
  1448. #else
  1449.     else if((win->win_flags&WIN_PAG_HZ) || hr>=100)
  1450.         lh=5;
  1451. #endif
  1452.     else if(hr>10)
  1453.         lh=4;
  1454.     else
  1455.         lh=3;
  1456.     win->win_over-=win->lh_wid-lh;
  1457.     win->numc+=win->lh_wid-lh;
  1458.     win->lh_wid=lh;
  1459. }
  1460.  
  1461. static void
  1462. move_cursor_to FUN3(struct window *,win, CELLREF, r,CELLREF, c)
  1463. {
  1464.     int cc;
  1465.     int cursor_col;
  1466.  
  1467.     cursor_col=win->win_over;
  1468.     for(cc=win->screen.lc;cc<c;cc++)
  1469.         cursor_col+=get_width(cc);
  1470.     move(win->win_down+r-win->screen.lr,cursor_col);
  1471. }
  1472.  
  1473. void
  1474. pr_cell FUN3(CELLREF, r, CELLREF, c, CELL *, cp)
  1475. {
  1476.     int xx,yy;
  1477.     struct window *win = (void *)0;
  1478.  
  1479.     getyx(stdscr,yy,xx);
  1480.     for(win=wins;win<&wins[nwin];win++) {
  1481.         if(   r<win->screen.lr || r>win->screen.hr
  1482.             || c<win->screen.lc || c>win->screen.hc)
  1483.             continue;
  1484.  
  1485.         pr_cell_win(win,r,c,cp);
  1486.     }
  1487.     move(yy,xx);
  1488. }
  1489.  
  1490. static void
  1491. pr_cell_win FUN4(struct window *,win, CELLREF, r, CELLREF, c, CELL *, cp)
  1492. {
  1493.     int glowing;
  1494.     int lenstr;
  1495.     int j;
  1496.     int wid,wwid;
  1497.     char *ptr;
  1498.  
  1499.     wid=get_width(c);
  1500.     if(!wid)
  1501.         return;
  1502.     if(wid>win->numc)
  1503.         wid=win->numc;
  1504.     glowing = (r==curow && c==cucol && win==cwin);
  1505.  
  1506.     ptr=print_cell(cp);
  1507. #ifdef TEST
  1508.     if(!ptr)
  1509.         panic("print_cell returned 0");
  1510. #endif
  1511.     move_cursor_to(win,r,c);
  1512.     if(glowing)
  1513.         standout();
  1514.     j=GET_JST(cp);
  1515.     if(j==JST_DEF)
  1516.         j=default_jst;
  1517.     lenstr=strlen(ptr);
  1518.  
  1519.     if(lenstr<=wid-1) {
  1520.         CELLREF ccl,cch;
  1521.  
  1522.         if(j==JST_LFT)
  1523.             printw("%-*.*s",wid, wid-1,ptr);
  1524.         else if(j==JST_RGT)
  1525.             printw("%*.*s ",wid-1, wid-1,ptr);
  1526.         else if(j==JST_CNT) {
  1527.             wid=(wid-1)-lenstr;
  1528.             printw("%*s%*s ",(wid+1)/2+lenstr,ptr,wid/2,"");
  1529.         }
  1530. #ifdef TEST
  1531.         else
  1532.             panic("Unknown justification");
  1533. #endif
  1534.         if(glowing)
  1535.             standend();
  1536.  
  1537.         if(lenstr==0 && c>win->screen.lc && find_slop(win->win_slops,r,c-1,&ccl,&cch)) {
  1538.             CELLREF ccdl,ccdh;
  1539.  
  1540.             if(find_slop(win->win_slops, r,c,&ccdl,&ccdh) && ccdl==c) {
  1541.                 kill_slop(win->win_slops, r,ccdl,ccdh);
  1542.                 for(;ccdh!=ccdl;--ccdh)
  1543.                     if(ccdh!=c && (wid=get_width(ccdh))) {
  1544.                         move_cursor_to(win,r,ccdh);
  1545.                         printw("%*s",wid,"");
  1546.                     }
  1547.             }
  1548.             kill_slop(win->win_slops, r,ccl,cch);
  1549.             pr_cell(r,ccl,find_cell(r,ccl));
  1550.         } else if(find_slop(win->win_slops, r,c,&ccl,&cch)) {
  1551.             kill_slop(win->win_slops, r,ccl,cch);
  1552.             for(;cch!=ccl;--cch)
  1553.                 if(cch!=c && (wid=get_width(cch))) {
  1554.                     move_cursor_to(win,r,cch);
  1555.                         printw("%*s",wid,"");
  1556.                 }
  1557.             pr_cell(r,ccl,find_cell(r,ccl));
  1558.         }
  1559.     } else {
  1560.         CELLREF cc=c;
  1561.         CELL *ccp;
  1562.         CELLREF ccl,cch;
  1563.  
  1564.         for(wwid=wid;lenstr>wwid-1;wwid+=get_width(cc)) {
  1565.             if(   ++cc>win->screen.hc
  1566.                || (   ccp=find_cell(r,cc))
  1567.                    && GET_TYP(ccp)
  1568.                    && (   GET_FMT(ccp)!=FMT_HID
  1569.                    || (   GET_FMT(ccp)==FMT_DEF
  1570.                        && default_fmt!=FMT_HID))) {
  1571.                 --cc;
  1572.                 break;
  1573.             }
  1574.         }
  1575.  
  1576.         if(lenstr>wwid-1)
  1577.              if(GET_TYP(cp)==TYP_FLT)
  1578.                 ptr=adjust_prc(ptr,cp,wwid-1,wid-1,j);
  1579.             else if(GET_TYP(cp)==TYP_INT)
  1580.                 ptr=(char *)numb_oflo;
  1581.  
  1582.         if(wwid==1) {
  1583.             addch(' ');
  1584.             if(glowing)
  1585.                 standend();
  1586.         } else if(wwid==wid) {
  1587.             printw("%-*.*s ",wwid-1,wwid-1,ptr);
  1588.             if(glowing)
  1589.                 standend();
  1590.         } else if(glowing) {
  1591.             printw("%.*s",wid,ptr);
  1592.             standend();
  1593.             printw("%-*.*s ",wwid-wid-1,wwid-wid-1,ptr+wid);
  1594.         } else if(r==curow && (cucol>c && cucol<=cc)) {
  1595.             CELLREF ctmp;
  1596.             int w_left;
  1597.             int w_here;
  1598.  
  1599.             w_left=wid;
  1600.             for(ctmp=c+1;ctmp<cucol;ctmp++)
  1601.                 w_left+=get_width(ctmp);
  1602.             printw("%.*s",w_left,ptr);
  1603.             standout();
  1604.             w_here=get_width(cucol);
  1605.             if(wwid>w_left+w_here) {
  1606.                 printw("%-*.*s",w_here,w_here,ptr+w_left);
  1607.                 standend();
  1608.                 printw("%-*.*s ",wwid-(w_left+w_here)-1,wwid-(w_left+w_here)-1,ptr+w_left+w_here);
  1609.             } else {
  1610.                 printw("%-*.*s",w_here,w_here-1,ptr+w_left);
  1611.                 standend();
  1612.             }
  1613.         } else
  1614.             printw("%-*.*s ",wwid-1,wwid-1,ptr);
  1615.  
  1616.         if(find_slop(win->win_slops, r,c,&ccl,&cch)) {
  1617.             change_slop(win->win_slops, r,ccl,cch,c,cc);
  1618.             for(;cch>cc;--cch)
  1619.                 if(wid=get_width(cch)) {
  1620.                     move_cursor_to(win,r,cch);
  1621.                     printw("%*s",wid,"");
  1622.                 }
  1623.             for(cch=c-1;cch>ccl;--cch)
  1624.                 if(wid=get_width(cch)) {
  1625.                     move_cursor_to(win,r,cch);
  1626.                     printw("%*s",wid,"");
  1627.                 }
  1628.             if(ccl!=c)
  1629.                 pr_cell(r,ccl,find_cell(r,ccl));
  1630.         } else
  1631.             set_slop((VOIDSTAR *)(&(win->win_slops)), r,c,cc);
  1632.     }
  1633.     if(glowing)
  1634.         cur_status();
  1635. }
  1636. void
  1637. cur_status FUN0()
  1638. {
  1639.     CELL *cp;
  1640.     char *dec;
  1641.     char *ptr;
  1642.     static char hmbuf[40];
  1643.     int wid;
  1644.     int plen;
  1645.     int dlen;
  1646.     int yy,xx;
  1647.  
  1648.     if(!status)
  1649.         return;
  1650.     getyx(stdscr,yy,xx);
  1651.     move(status-1,0);
  1652.     wid=COLS-2;
  1653.  
  1654.     if(mkrow!=NON_ROW) {
  1655.         struct rng r;
  1656.  
  1657.         addch('*');
  1658.         --wid;
  1659.         set_rng(&r,curow,cucol,mkrow,mkcol);
  1660.         ptr=range_name(&r);
  1661.     } else
  1662.         ptr=cell_name(curow,cucol);
  1663.  
  1664.     addstr(ptr);
  1665.     wid-=strlen(ptr);
  1666.  
  1667.     if(how_many!=1) {
  1668.         sprintf(hmbuf," {%u}",how_many);
  1669.         addstr(hmbuf);
  1670.         wid-=strlen(hmbuf);
  1671.     }
  1672.  
  1673.     if((cp=find_cell(curow,cucol)) && cp->cell_formula) {
  1674.         dec=decomp(curow,cucol,cp);
  1675.         dlen=strlen(dec);
  1676.     } else {
  1677.         dec=0;
  1678.         dlen=0;
  1679.     }
  1680.  
  1681.     ptr=cell_value_string(curow,cucol);
  1682.     plen=strlen(ptr);
  1683.  
  1684.     if(dec) {
  1685.         wid-=4;
  1686.         if(dlen+plen>wid) {
  1687.             if(plen+3>wid)
  1688.                 printw(" %.*s... [...]",wid-6,ptr);
  1689.             else
  1690.                 printw(" %s [%.*s...]",ptr,wid-plen-3,dec);
  1691.         } else
  1692.             printw(" %s [%s]",ptr,dec);
  1693.         decomp_free();
  1694.     } else if(plen) {
  1695.         --wid;
  1696.         if(plen>wid)
  1697.             printw(" %.*s...",wid-3,ptr);
  1698.         else
  1699.             printw(" %s",ptr);
  1700.     }
  1701.  
  1702.     clrtoeol();
  1703.     move(yy,xx);
  1704. }
  1705.  
  1706. static void
  1707. display_cell_cursor FUN0()
  1708. {
  1709.     int cc;
  1710.     int cursor_row;
  1711.     int cursor_col;
  1712.     int cwid;
  1713. #ifndef __TURBOC__
  1714.     int n;
  1715. #endif
  1716.  
  1717.     cursor_col=cwin->win_over;
  1718.     for(cc=cwin->screen.lc;cc<cucol;cc++)
  1719.       {
  1720.         cursor_col+=get_width(cc);
  1721.       }
  1722.     cursor_row=cwin->win_down+curow-cwin->screen.lr;
  1723.     cwid=get_width(cucol);
  1724.     if(cwid>cwin->numc)
  1725.         cwid=cwin->numc;
  1726. #ifdef __TURBOC__
  1727.     hack_standout(1,cursor_row,cursor_col,cwid);
  1728. #else
  1729.     move(cursor_row,cursor_col);
  1730.     standout();
  1731.     for(n=cwid;n;n--)
  1732. #ifdef A_STANDOUT
  1733.         addch(inch()|A_STANDOUT);
  1734. #else
  1735.         addch(inch());
  1736. #endif
  1737.     standend();
  1738. #endif
  1739. }
  1740.  
  1741. static void
  1742. hide_cell_cursor FUN0()
  1743. {
  1744.     int cc;
  1745.     int cursor_row;
  1746.     int cursor_col;
  1747.     int cwid;
  1748. #ifndef __TURBOC__
  1749.     int n;
  1750. #endif
  1751.  
  1752.     cursor_col=cwin->win_over;
  1753.     for(cc=cwin->screen.lc;cc<cucol;cc++)
  1754.       {
  1755.         cursor_col+=get_width(cc);
  1756.       }
  1757.     cursor_row=cwin->win_down+curow-cwin->screen.lr;
  1758.     cwid=get_width(cucol);
  1759.     if(cwid>cwin->numc)
  1760.         cwid=cwin->numc;
  1761. #ifdef __TURBOC__
  1762.     hack_standout(0,cursor_row,cursor_col,cwid);
  1763. #else
  1764.     move(cursor_row,cursor_col);
  1765.     for(n=cwid;n;n--)
  1766. #ifdef SYSV
  1767.         addch(inch()&~A_STANDOUT);
  1768. #else
  1769.         addch(inch());
  1770. #endif
  1771. #endif
  1772. }
  1773.  
  1774. #ifdef __TURBOC__
  1775. static void
  1776. hack_standout FUN4(int,standp, int,rown, int,coln, int,cols)
  1777. {
  1778.     char buf[COLS*2];
  1779.     char *ptr;
  1780.     int n;
  1781.  
  1782.     standp = standp ? 0x7<<4 : 0x7;
  1783.     rown++;
  1784.     coln++;
  1785.     gettext(coln,rown,coln+cols-1,rown,buf);
  1786.     ptr=buf+1;
  1787.     n=cols;
  1788.     while(n--) {
  1789.         *ptr= standp;
  1790.         ptr+=2;
  1791.     }
  1792.     puttext(coln,rown,coln+cols-1,rown,buf);
  1793. }
  1794.  
  1795. static void
  1796. printw FUN1N(char *,str)
  1797. {
  1798.     va_list ap;
  1799.     char text[COLS+1];
  1800.  
  1801.     var_start(ap,str);
  1802.     vsprintf(text,str,ap);
  1803.     addstr(text);
  1804.     va_end(ap);
  1805. }
  1806.  
  1807. #endif
  1808.  
  1809. int
  1810. get_chr_prompt FUN1(char *,prompt)
  1811. {
  1812.     mvaddstr(input-1,0,prompt);
  1813.     clrtoeol();
  1814.     topclear=2;
  1815.     refresh();
  1816.     return get_chr();
  1817. }
  1818.  
  1819. void
  1820. error_msg FUN1N(char *,str)
  1821. {
  1822.     va_list foo;
  1823.     char buf[1000];
  1824.     /* Sigh.  What I'd give for vprintw() */
  1825.  
  1826. #ifdef TEST
  1827.     extern int isatty();
  1828.  
  1829.     if(!dbg_do_stderr)
  1830.     dbg_do_stderr= isatty(fileno(stderr)) ? 1 : 2;
  1831. #endif
  1832.     var_start(foo,str);
  1833.     vsprintf(buf,str,foo);
  1834. #ifdef TEST
  1835.     if(dbg_do_stderr==2) {
  1836.         fputs(buf,stderr);
  1837.         putc('\n',stderr);
  1838.         fflush(stderr);
  1839.     }
  1840. #endif
  1841.     if(textout==2) {
  1842.         mvaddstr(input-1,COLS-7,"[MORE]");
  1843.         (void)get_chr();
  1844.     } else
  1845.         textout=2;
  1846.     mvaddstr(input-1,0,buf);
  1847.     clrtoeol();
  1848.     topclear=1;
  1849.     refresh();
  1850. }
  1851.  
  1852. void
  1853. info_msg FUN1N(char *,str)
  1854. {
  1855.     va_list foo;
  1856.     char buf[1000];
  1857.     /* See previous comment */
  1858.  
  1859.     var_start(foo,str);
  1860.     vsprintf(buf,str,foo);
  1861.     if(!status) {
  1862.         if(textout==2) {
  1863.             mvaddstr(input-1,COLS-7,"[MORE]");
  1864.             (void)get_chr();
  1865.         }
  1866.         textout=1;
  1867.         mvaddstr(input-1,0,buf);
  1868.     } else        
  1869.         mvaddstr(status-1,0,buf);
  1870.     clrtoeol();
  1871.     refresh();
  1872. }
  1873. #ifndef amiga
  1874.  
  1875. void
  1876. _putchar FUN1(int, ch)
  1877. {
  1878.     (void)putc(ch,stdout);
  1879.     /* (void)putchar(ch); */
  1880. }
  1881. #endif
  1882.  
  1883. #ifndef __TURBOC__
  1884. static void
  1885. beep FUN0()
  1886. {
  1887. #ifdef SYSV
  1888.     _putchar('\007');
  1889. #else
  1890.     static char *vb;
  1891.     static called;
  1892.  
  1893.     if(!called) {
  1894.         called++;
  1895.         vb=getcap("vb");
  1896.     }
  1897.     if(vb) {
  1898.         _puts(vb);
  1899.     } else {
  1900.         _putchar('\007');
  1901.     }
  1902. #endif
  1903. }
  1904. #endif
  1905.  
  1906. void
  1907. shift_linked_window FUN2(long,dn, long,ov)
  1908. {
  1909.     struct window *win;
  1910.  
  1911.     win=cwin;
  1912.     while(win->win_linked!=-1) {
  1913.         win= &wins[win->win_linked];
  1914.         if(win==cwin)    /* Loop check! */
  1915.             return;
  1916.         if((win->win_flags&WIN_LCK_VT)==0)
  1917.             win->curow+=dn;
  1918.         if((win->win_flags&WIN_LCK_HZ)==0)
  1919.             win->cucol+=ov;
  1920.         if(   win->curow<win->screen.lr || win->curow>win->screen.hr
  1921.            || win->cucol<win->screen.lc || win->cucol>win->screen.hc)
  1922.             recenter_window(win);
  1923.     }
  1924. }
  1925.  
  1926. int
  1927. move_cell_cursor FUN2(CELLREF,rr, CELLREF,cc)
  1928. {
  1929.     int ret;
  1930.     int cx,cy;
  1931.  
  1932.     if(cwin->win_linked!=-1)
  1933.         shift_linked_window((long)rr-curow,(long)cc-cucol);
  1934.     if(   rr<cwin->screen.lr || rr>cwin->screen.hr
  1935.        || cc<cwin->screen.lc || cc>cwin->screen.hc) {
  1936.         cwin->curow=curow=rr;
  1937.         cwin->cucol=cucol=cc;
  1938.         recenter_window(cwin);
  1939.         disp_scrn();
  1940.         ret=1;
  1941.     } else {
  1942.         getyx(stdscr,cy,cx);
  1943.         hide_cell_cursor();
  1944.         curow=rr;
  1945.         cucol=cc;
  1946.         display_cell_cursor();
  1947.         cur_status();
  1948.         move(cy,cx);
  1949.         ret=0;
  1950.     }
  1951.     if(get_width(cucol)==0)
  1952.              find_nonzero_width(cwin);
  1953.     return ret;
  1954. }
  1955.  
  1956. static void
  1957. find_nonzero_width FUN1(struct window *,win)
  1958. {
  1959.     CELLREF cc;
  1960.     unsigned short n;
  1961.  
  1962.     cc=cucol;
  1963.  
  1964.     if(cc<win->screen.hc) {
  1965.         cc++;
  1966.         while((n=get_width(cc))==0) {
  1967.             if(cc==win->screen.hc)
  1968.                 break;
  1969.             cc++;
  1970.         }
  1971.         if(n) {
  1972.             cucol=cc;
  1973.             return;
  1974.         }
  1975.     }
  1976.     if(cc>win->screen.lc) {
  1977.              --cc;
  1978.         while((n=get_width(cc))==0) {
  1979.             if(cc==win->screen.lc)
  1980.                 break;
  1981.             --cc;
  1982.         }
  1983.         if(n) {
  1984.             cucol=cc;
  1985.             return;
  1986.         }
  1987.     }
  1988. }
  1989.  
  1990.  
  1991. void
  1992. recenter_all_win FUN0()
  1993. {
  1994.     int n;
  1995.  
  1996.     cwin->curow=curow;
  1997.     cwin->cucol=cucol;
  1998.     for(n=0;n<nwin;n++)
  1999.         recenter_window(&wins[n]);
  2000.     disp_scrn();
  2001. }
  2002.  
  2003. void
  2004. recenter_cur_win FUN0()
  2005. {
  2006.     cwin->curow=curow;
  2007.     cwin->cucol=cucol;
  2008.     recenter_window(cwin);
  2009.     disp_scrn();
  2010. }
  2011.  
  2012. static void
  2013. recenter_window FUN1(struct window *,win)
  2014. {
  2015.     CELLREF lr,hr,lc,hc;
  2016.     CELLREF rr;
  2017.     unsigned short w,ww;
  2018.     unsigned short n;
  2019.     unsigned short totwid = 0;
  2020.     int more;
  2021.  
  2022.     if(get_width(win->cucol)==0)
  2023.         find_nonzero_width(win);
  2024.  
  2025.     if(win->win_flags&WIN_PAG_VT) {
  2026.         lr=MIN_ROW+win->numr * ((win->curow-MIN_ROW)/win->numr);
  2027.         hr = (lr>MAX_ROW-win->numr) ? MAX_ROW : lr+win->numr-1;
  2028.     } else {
  2029.         rr=win->numr/2;
  2030.         lr= (win->curow<=rr) ? MIN_ROW : (win->curow-rr);
  2031.         if(lr>=MAX_ROW-win->numr) {
  2032.             hr=MAX_ROW;
  2033.             lr=hr+1-win->numr;
  2034.         } else
  2035.             hr=lr+win->numr-1;
  2036.     }
  2037.     set_numcols(win,hr);
  2038.  
  2039.     if(win->win_flags&WIN_PAG_HZ) {
  2040.         lc=hc=MIN_COL;
  2041.         w=get_width(hc);
  2042.         for(;;) {
  2043.             ww=get_width(hc+1);
  2044.             while(w+ww<=win->numc && hc<MAX_COL) {
  2045.                 hc++;
  2046.                 w+=ww;
  2047.                 ww=get_width(hc+1);
  2048.             }
  2049.             if(hc>=win->cucol)
  2050.                 break;
  2051.             hc++;
  2052.             lc=hc;
  2053.             w=ww;
  2054.         }
  2055.         if(lc>win->cucol || hc>MAX_COL) {
  2056.             error_msg("Can't find a non-zero-width column in recenter_window()");
  2057.             /* ... */
  2058.         }
  2059.     } else {
  2060.         lc=hc=win->cucol;
  2061.         n=totwid=get_width(win->cucol);
  2062.         do {
  2063.             if(lc>MIN_COL && totwid+(n=get_width(lc-1))<win->numc) {
  2064.                 --lc;
  2065.                 totwid+=n;
  2066.                 more=1;
  2067.             } else
  2068.                 more=0;
  2069.             if(hc<MAX_COL && totwid+(n=get_width(hc+1))<win->numc) {
  2070.                 hc++;
  2071.                 totwid+=n;
  2072.                 more++;
  2073.             }
  2074.         } while(more);
  2075.     }
  2076.     while(get_width(lc)==0)
  2077.         lc++;
  2078.     while(get_width(hc)==0)
  2079.         --(hc);
  2080.  
  2081.     win->screen.lc=lc;
  2082.     win->screen.hc=hc;
  2083.     win->screen.lr=lr;
  2084.     win->screen.hr=hr;
  2085. }
  2086.  
  2087.  
  2088. int
  2089. scroll_cell_cursor FUN1(int, magic)
  2090. {
  2091.     int off_dn,off_rt;
  2092.     int n=0;
  2093.     int totwid;
  2094.  
  2095.     struct rng s;
  2096.     CELLREF cr,cc;
  2097.     unsigned short w;
  2098.     int over,down;
  2099.  
  2100.     over=colmagic[magic]*how_many;
  2101.     down=rowmagic[magic]*how_many;
  2102.     if(down) {
  2103.         off_dn=curow-cwin->screen.lr;
  2104.         n=down*cwin->numr;
  2105.         if(n>MAX_ROW-MIN_ROW) {
  2106.             error_msg(down>0 ? "Can't scroll down" : "Can't scroll up");
  2107.             return 0;
  2108.         }
  2109.         if(down>0) {
  2110.             if(cwin->screen.lr>MAX_ROW-n) {
  2111.                 error_msg("Can't scroll down");
  2112.                 return 0;
  2113.             }
  2114.  
  2115.             if(cwin->screen.hr>MAX_ROW-n) {
  2116.                 s.hr=MAX_ROW;
  2117.                 s.lr= (cwin->win_flags&WIN_PAG_VT) ? cwin->screen.lr+n : 1+s.hr-cwin->numr;
  2118.                 cr= (off_dn>s.hr-s.lr) ? MAX_ROW : s.lr+off_dn;
  2119.             } else {
  2120.                 s.lr=cwin->screen.lr+n;
  2121.                 s.hr=cwin->screen.hr+n;
  2122.                 cr=s.lr+off_dn;
  2123.             }
  2124.         } else {
  2125.             if(cwin->screen.hr<MIN_ROW-n) {
  2126.                 error_msg("Can't scroll up");
  2127.                 return 0;
  2128.             }
  2129.  
  2130.             if((cwin->win_flags&WIN_PAG_VT) && cwin->screen.hr==MAX_ROW) {
  2131.                 s.lr=cwin->screen.lr+n;
  2132.                 s.hr=s.lr+cwin->numr-1;
  2133.             } else if(cwin->screen.lr<MIN_ROW-n) {
  2134.                 s.lr=MIN_ROW;
  2135.                 s.hr=s.lr+cwin->numr-1;
  2136.             } else {
  2137.                 s.lr=cwin->screen.lr+n;
  2138.                 s.hr=cwin->screen.hr+n;
  2139.             }
  2140.             cr=s.lr+off_dn;
  2141.         }
  2142.  
  2143.         set_numcols(cwin,s.hr);
  2144.     } else {
  2145.         s.lr=cwin->screen.lr;
  2146.         s.hr=cwin->screen.hr;
  2147.         cr=curow;
  2148.     }
  2149.  
  2150.     off_rt=cucol-cwin->screen.lc;
  2151.  
  2152.     if(over>0) {
  2153.         if(cwin->screen.hc==MAX_COL) {
  2154.             error_msg("Can't scroll right");
  2155.             return 0;
  2156.         }
  2157.  
  2158.         for(s.lc=s.hc=cwin->screen.hc+1;;s.lc= ++s.hc) {
  2159.             --over;
  2160.             totwid=get_width(s.lc);
  2161.             while(s.hc<MAX_COL && totwid+(n=get_width(s.hc+1))<=cwin->numc) {
  2162.                 s.hc++;
  2163.                 totwid+=n;
  2164.             }
  2165.             if(!over || s.hc==MAX_COL)
  2166.                 break;
  2167.         }
  2168.         if(!(cwin->win_flags&WIN_PAG_HZ)) {
  2169.             while(s.lc>MIN_COL && totwid+(n=get_width(s.lc-1))<=cwin->numc) {
  2170.                 s.lc--;
  2171.                 totwid+=n;
  2172.                 off_rt++;
  2173.             }
  2174.         }
  2175.         cc= (s.hc-s.lc<off_rt) ? s.hc : s.lc+off_rt;
  2176.     } else if(over<0) {
  2177.         if(cwin->screen.lc==MIN_COL) {
  2178.             error_msg("Can't scroll left");
  2179.             return 0;
  2180.         }
  2181.  
  2182.         if(cwin->win_flags&WIN_PAG_HZ) {
  2183.             /* This is tricky! */
  2184.             int n_over;
  2185.             unsigned short ww = 0;
  2186.  
  2187.             n_over=0;
  2188.             for(s.lc=s.hc=MIN_COL,w=get_width(s.hc);
  2189.                 ;
  2190.                 s.lc= ++s.hc,w=ww,n_over++) {
  2191.                 while(s.hc<MAX_COL && w+(ww=get_width(s.hc+1))<=cwin->numc) {
  2192.                     s.hc++;
  2193.                     w+=ww;
  2194.                 }
  2195.                 if(s.hc>=cucol)
  2196.                     break;
  2197.             }
  2198.             n_over+=over;
  2199.             if(n_over<0) {
  2200.                 error_msg("Can't scroll left");
  2201.                 return 0;
  2202.             }
  2203.  
  2204.             for(s.lc=s.hc=MIN_COL,w=get_width(s.hc);
  2205.                 ;
  2206.                 s.lc=s.hc+1,s.hc++,w=ww) {
  2207.                 ww=get_width(s.hc+1);
  2208.                 while(w+ww<=cwin->numc && s.hc<MAX_COL) {
  2209.                     s.hc++;
  2210.                     w+=ww;
  2211.                     ww=get_width(s.hc+1);
  2212.                 }
  2213.                 if(!n_over--)
  2214.                     break;
  2215.             }
  2216.             over=0;
  2217.             cc= (s.hc-s.lc<off_rt) ? s.hc : s.lc+off_rt;
  2218.         } else {
  2219.             for(s.lc=s.hc=cwin->screen.lc-1;;s.hc= --s.lc) {
  2220.                 over++;
  2221.                 totwid=get_width(s.lc);
  2222.                 while(s.lc>MIN_COL && totwid+(n=get_width(s.lc-1))<=cwin->numc) {
  2223.                     s.lc--;
  2224.                     totwid+=n;
  2225.                 }
  2226.                 if(!over || s.lc==MIN_COL)
  2227.                     break;
  2228.             }
  2229.             if(s.lc==MIN_COL) {
  2230.                 while(s.hc<MAX_COL && totwid+(n=get_width(s.hc+1))<=cwin->numc) {
  2231.                     s.hc++;
  2232.                     totwid+=n;
  2233.                 }
  2234.             }
  2235.             cc= (s.hc-s.lc<off_rt) ? s.lc : s.lc+off_rt;
  2236.         }
  2237.     } else if(!(cwin->win_flags&WIN_PAG_HZ)) {
  2238.         /* If page_scroll, we don't have to bother with this.
  2239.            It'll fit.  That's all. . . */
  2240.         totwid=0;
  2241.         s.lc=cwin->screen.lc;
  2242.         s.hc=cwin->screen.hc;
  2243.         cc=cucol;
  2244.  
  2245.         /* This is tricky:  ;n<=s.hc;  won't work if s.hc==MAX_CELLREF */
  2246.         for(n=s.lc;;n++) {
  2247.             totwid+=get_width(n);
  2248.             if(n==s.hc)
  2249.                 break;
  2250.         }
  2251.         while(cwin->numc<totwid) {
  2252.             if(cucol==s.lc)
  2253.                 totwid-=get_width(s.hc--);
  2254.             else
  2255.                 totwid-=get_width(s.lc++);
  2256.         }
  2257.         while(s.hc<MAX_COL && totwid+(n=get_width(s.hc+1))<=cwin->numc) {
  2258.             ++s.hc;
  2259.             totwid+=n;
  2260.         }
  2261.         while(s.lc>MIN_COL && totwid+(n=get_width(s.lc-1))<=cwin->numc) {
  2262.             --s.lc;
  2263.             totwid+=n;
  2264.         }
  2265.     } else {
  2266.         cwin->screen.lr=s.lr;
  2267.         cwin->screen.hr=s.hr;
  2268.         if(cwin->win_linked!=-1)
  2269.             shift_linked_window((long)cr-curow,(long)0);
  2270.         curow=cr;
  2271.         disp_scrn();
  2272.         return 1;
  2273.     }
  2274.  
  2275.     if(over) {
  2276.         error_msg(over>0 ? "Can't scroll right" : "Can't scroll left");
  2277.         return 0;
  2278.     }
  2279.  
  2280.     while(get_width(s.lc)==0)
  2281.         s.lc++;
  2282.     while(get_width(s.hc)==0)
  2283.         --(s.hc);
  2284.  
  2285.     if(cwin->win_linked!=-1)
  2286.         shift_linked_window((long)cr-curow,(long)cc-cucol);
  2287.  
  2288.     cwin->screen=s;
  2289.     curow=cr;
  2290.     cucol=cc;
  2291.  
  2292.     if(get_width(cc)==0)
  2293.         find_nonzero_width(cwin);
  2294.  
  2295.     disp_scrn();
  2296.     return 1;
  2297. }
  2298.  
  2299. void
  2300. read_mp_windows FUN1(char *,line)
  2301. {
  2302.     int wnum=0;
  2303.     char *text;
  2304.     CELLREF nrow=NON_ROW,ncol=NON_COL;
  2305.     char *split=0;
  2306.     char *opts=0;
  2307.     struct window *win;
  2308.  
  2309.     text=line;
  2310.     for(;;) {
  2311.         switch(*text++) {
  2312.                 /* Window Number */
  2313.         case 'N':
  2314.             wnum=astol(&text);
  2315.             break;
  2316.                 /* Cursor At */
  2317.         case 'A':
  2318.             nrow=astol(&text);
  2319.             ncol=astol(&text);
  2320.             break;
  2321.                 /* JF: Window options */
  2322.         case 'O':
  2323.             opts=text;
  2324.             while(*text && *text!=';')
  2325.                 text++;
  2326.             break;
  2327.                 /* Split into two windows */
  2328.         case 'S':
  2329.             split=text;
  2330.             while(*text && *text!=';')
  2331.                 text++;
  2332.             break;
  2333.                 /* Set Colors NOT supported */
  2334.         case 'C':
  2335.             while(*text && *text!=';')
  2336.                 text++;
  2337.             break;
  2338.                 /* Alternate border NOT supported. . . */
  2339.         case 'B':
  2340.             break;
  2341.         default:
  2342.             --text;
  2343.             break;
  2344.         }
  2345.         if(*text=='\0' || *text=='\n')
  2346.             break;
  2347.         if(*text!=';') {
  2348.             char *bad;
  2349.  
  2350.             bad=text;
  2351.             while(*text && *text!=';')
  2352.                 text++;
  2353.             if(*text)
  2354.                 *text++='\0';
  2355.             error_msg("Unknown SYLK window cmd: %s",bad);
  2356.             if(!*text)
  2357.                 break;
  2358.         } else
  2359.             *text++='\0';
  2360.     }
  2361.     if(wnum<1 || wnum>nwin) {
  2362.         error_msg("Window %d out of range in SYLK line %s",wnum,line);
  2363.         return;
  2364.     }
  2365.     --wnum;
  2366.     win= &wins[wnum];
  2367.     if(nrow!=NON_ROW) {
  2368.         win->curow=nrow;
  2369.         win->cucol=ncol;
  2370.         if(win==cwin) {
  2371.             curow=nrow;
  2372.             cucol=ncol;
  2373.         }
  2374.         recenter_window(win);
  2375.     }
  2376.     if(split) {
  2377.         int hv = 0;
  2378.         int where;
  2379.         int link;
  2380.         struct window *new;
  2381.  
  2382.         switch(*split++) {
  2383.         case 'H':
  2384.         case 'h':
  2385.             hv=1;
  2386.             break;
  2387.         case 'v':
  2388.         case 'V':
  2389.             hv=0;
  2390.             break;
  2391.         case 't':
  2392.         case 'T':
  2393.             error_msg("Window split titles not supported");
  2394.             return;
  2395.         default:
  2396.             break;
  2397.         }
  2398.         if(*split=='L') {
  2399.             link=wnum;
  2400.             split++;
  2401.         } else
  2402.             link= -1;
  2403.  
  2404.         where=astol(&split);
  2405.  
  2406.         if(hv ? where>=win->numr : where>=win->numc)
  2407.             error_msg("Can't split window: screen too small");
  2408.  
  2409.         nwin++;
  2410.  
  2411.         wins=ck_realloc(wins,nwin*sizeof(struct window));
  2412.         cwin=wins;
  2413.         win= &wins[wnum];
  2414.         new= &wins[nwin-1];
  2415.  
  2416.         win->numc-=(hv ? 0 : where);
  2417.         win->numr-=(hv ? where : 0);
  2418.         win->curow=curow;
  2419.         win->cucol=cucol;
  2420.  
  2421.         new->win_flags = WIN_EDGES|WIN_EDGE_REV;/* Mplan defaults */
  2422.         new->lh_wid=0;    /* For now */
  2423.         new->win_linked=link;
  2424.  
  2425.         new->win_over=win->win_over + (hv ?  -win->lh_wid : win->numc);
  2426.         new->win_down=win->win_down + (hv ? win->numr+1 : 0);
  2427.         new->numc=(hv ? win->numc+win->lh_wid : where);
  2428.         new->numr=(hv ? where-1 : win->numr);
  2429.         new->curow=curow;
  2430.         new->cucol=cucol;
  2431.         set_numcols(new,curow);
  2432.         recenter_window(win);
  2433.         recenter_window(new);
  2434.     }
  2435.     if(opts) {
  2436.         char *np;
  2437.  
  2438.         while(np=index(opts,',')) {
  2439.             *np='\0';
  2440.             set_options(opts);
  2441.             *np++=';';
  2442.             opts=np;
  2443.         }
  2444.         if(np=rindex(opts,'\n'))
  2445.             *np='\0';
  2446.         set_options(opts);
  2447.     }
  2448. }
  2449.  
  2450. void
  2451. write_mp_windows FUN1(FILE *,fp)
  2452. {
  2453.     int n;
  2454.     char buf[90];
  2455.  
  2456.     cwin->curow=curow;
  2457.     cwin->cucol=cucol;
  2458.     fprintf(fp,"O;status %d\n",status);
  2459.     if(nwin>1) {
  2460.         /* ... */
  2461.     }
  2462.     for(n=0;n<nwin;n++) {
  2463.         buf[0]='\0';
  2464.         if(wins[n].win_flags&WIN_LCK_HZ)
  2465.             strcat(buf,",lockh");
  2466.         if(wins[n].win_flags&WIN_LCK_VT)
  2467.             strcat(buf,",lockv");
  2468.         if(wins[n].win_flags&WIN_PAG_HZ)
  2469.             strcat(buf,",pageh");
  2470.         if(wins[n].win_flags&WIN_PAG_VT)
  2471.             strcat(buf,",pagev");
  2472.         if(wins[n].win_flags&WIN_EDGE_REV)
  2473.             strcat(buf,",standout");
  2474.         if((wins[n].win_flags&WIN_EDGES)==0)
  2475.             strcat(buf,",noedges");
  2476.         fprintf(fp,"W;N%d;A%u %u;C%d %d %d;O%s\n",n+1,wins[n].curow,wins[n].cucol,7,0,7,buf+1);
  2477.     }
  2478. }
  2479.